/*
 * Mapear.java
 *
 * Created on 22 de Junho de 2007, 00:32
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.jerm.Mapeamento;

import java.util.HashMap;
import java.util.PriorityQueue;

import org.jerm.Interface.JGraph_Diagrama.Aresta;
import org.jerm.Interface.JGraph_Diagrama.BlocoAtributosGraphCell;
import org.jerm.Interface.JGraph_Diagrama.BlocoGraphCell;
import org.jerm.Interface.JGraph_Diagrama.Entidade;
import org.jerm.Interface.JGraph_Diagrama.Heranca;
import org.jerm.Interface.JGraph_Diagrama.MyGraph;
import org.jerm.Interface.JGraph_Diagrama.Relacionamento;
import org.jerm.Mapeamento.Atributos.Atributo;
import org.jerm.Mapeamento.Atributos.AtributoSerial;
import org.jerm.Mapeamento.Atributos.FK;
import org.jerm.Mapeamento.Tabelas.Tabela;
import org.jgraph.graph.DefaultPort;

/**
 *
 * @author tiagofalcao
 */
public class Mapear {
    
    private MyGraph graph;
    
    private Fila EntidadeNH;
    private Fila EntidadeH;
    private Fila EntidadeF;
    private Fila Relacionamentos;
    
    private Object[] Arestas;
    private Object[] Vertices;
    
    private HashMap<BlocoAtributosGraphCell,Tabela> Tabelas;
    private HashMap<BlocoGraphCell,BlocoAtributosGraphCell> Herda;
    
    
    /** Creates a new instance of Mapear */
    public Mapear(MyGraph graph) {
        EntidadeNH=new Fila();
        EntidadeH=new Fila();
        EntidadeF=new Fila();
        Relacionamentos=new Fila();
        Tabelas=new HashMap();
        Herda=new HashMap();
        this.graph=graph;
        
        Vertices=graph.getGraphLayoutCache ().getCells(false,true,false,false);
        Arestas=graph.getGraphLayoutCache ().getCells(false,false,false,true);
        int i=0;
        while(i<Vertices.length){
            if(Vertices[i].getClass()==Entidade.class){
                if(((Entidade)Vertices[i]).isFraca()){
                    EntidadeF.offer(Vertices[i]);
                    System.out.print("*");
                }else
                    EntidadeNH.offer(Vertices[i]);
            }else if(Vertices[i].getClass()==Relacionamento.class){
                    Relacionamentos.offer(Vertices[i]);
            }
            i++;
        }
        
        
        MapEntidadeNH();
        MapEntidadeH();
        MapEntidadeF();
        MapRelacionamento();
        
    }
    
    public Object getPaiHeranca(Object Bloco){
        Aresta aresta;
        Heranca h=null;
        int i=0;
        int j=0;
        while(i<Arestas.length){
            aresta=(Aresta)Arestas[i];
            if(((DefaultPort)aresta.getTarget()).getUserObject()==Bloco && 
                    ((DefaultPort)aresta.getSource()).getUserObject().getClass()==Heranca.class){
                h=(Heranca)((DefaultPort)aresta.getSource()).getUserObject();
                if(Herda.containsKey(h)){
                    return Herda.get(h);
                }else{
                    j=0;
                    while(j<Arestas.length){
                        aresta=(Aresta)Arestas[j];
                        if(((DefaultPort)aresta.getTarget()).getUserObject()==h && 
                                ((DefaultPort)aresta.getSource()).getUserObject().getClass()==Entidade.class){
                            Herda.put(h,(BlocoAtributosGraphCell)((DefaultPort)aresta.getSource()).getUserObject());
                            return ((DefaultPort)aresta.getSource()).getUserObject();
                        }
                        j++;
                    }
                }
            }
            i++;
        }
        return null;
    }
    
    private void MapEntidadeNH(){
        Entidade e=null;
        Tabela t=null;
        Object[] a=null;
        Object p;
        int i;
        System.out.println("NHerdadas: "+Integer.toString(EntidadeNH.size()));
        while(EntidadeNH.size() >0){
            e=(Entidade)EntidadeNH.poll();
            p=getPaiHeranca(e);
            if(p!=null){
                EntidadeH.offer(e);
                Herda.put(e,(BlocoAtributosGraphCell)p);
            }else{
                t=new Tabela(graph.convertValueToString(e));
                
                key2table(e,t);
//                // pega todos os atributos primos
//                a = e.valuesArrayAtributosPrimos();
//
//                // adiciona atributos primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addPrimo((Atributo)a[i]);
//                }

                atr2table(e,t);
//                // pega todos os atributos nao primos
//                a = e.valuesArrayAtributos();
//
//                // adiciona atributos nao primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addAtributo((Atributo)a[i]);
//                }
                
                Tabelas.put(e,t);
            }
        }
    }
    
    private void MapEntidadeH(){
        Entidade e=null;
        Tabela t=null;
        Object[] a=null;
        Object p=null;
        Tabela tr=null;
        int i;
        System.out.println("Herdadas: "+Integer.toString(EntidadeH.size()));
        while(EntidadeH.size()>0){
            e=(Entidade)EntidadeH.poll();
            p=Herda.get(e);
            if(!Tabelas.containsKey(p)){
                EntidadeH.offer(e);
            }else{
                tr=Tabelas.get(p);
                t=new Tabela(graph.convertValueToString(e));

                key2table(e,t);
                atr2table(e,t);
//                // pega todos os atributos nao primos
//                a = e.valuesArrayAtributos();
//
//                // adiciona atributos nao primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addAtributo((Atributo)a[i]);
//                }
                
                key2fkk(tr,t);
//                a=tr.getPrimo();
//                // adiciona atributos primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addFKPrimo(tr,(AtributoSerial)a[i]);
//                }
//                
//                a=tr.getFKPrimo();
//                // adiciona atributos primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addFKPrimo((FK)a[i]);
//                }
                
                Tabelas.put(e,t);
            }
        }
    }
    
    private Object getFracaDert(Object e){
        Aresta aresta;
        Heranca h=null;
        int i=0;
        while(i<Arestas.length){
            aresta=(Aresta)Arestas[i];
            if(((DefaultPort)aresta.getTarget()).getUserObject()==e && 
                    aresta.isTotal()){
                return ((DefaultPort)aresta.getSource()).getUserObject();
            }
            i++;
        }
        return null;
    }
    
    private void MapEntidadeF(){
        Entidade e=null;
        Relacionamento r=null;
        Tabela t=null;
        Object[] v=null;
        Object[] a=null;
        Tabela tr=null;
        int i;
        int j;
        System.out.println("Fracas: "+Integer.toString(EntidadeF.size()));
        while(EntidadeF.size()>0){
            e=(Entidade)EntidadeF.poll();
        
            t=new Tabela(graph.convertValueToString(e));

            key2table(e,t);
//            // pega todos os atributos nao primos
//            a = e.valuesArrayAtributosPrimos();
//
//            // adiciona atributos nao primos a relacao
//            for (i = 0; i < a.length; i++){
//                t.addPrimo((Atributo)a[i]);
//            }

            atr2table(e,t);
//            // pega todos os atributos nao primos
//            a = e.valuesArrayAtributos();
//
//            // adiciona atributos nao primos a relacao
//            for (i = 0; i < a.length; i++){
//                t.addAtributo((Atributo)a[i]);
//            }
            
            r=(Relacionamento)getFracaDert(e);
            v=graph.getAdjacentes(r,Aresta.SOURCE);
            j=0;
            while(j<v.length){
                if(v[j]!=e){
                    tr=Tabelas.get(v[j]);
                    
                    key2fkk(tr,t);

//                    a=tr.getPrimo();
//                    // adiciona atributos primos a relacao
//                    for (i = 0; i < a.length; i++){
//                        t.addFKPrimo(tr,(AtributoSerial)a[i]);
//                    }
//
//                    a=tr.getFKPrimo();
//                    // adiciona atributos primos a relacao
//                    for (i = 0; i < a.length; i++){
//                        t.addFKPrimo((FK)a[i]);
//                    }
                }
                j++;
            }
            
            Tabelas.put(e,t);
        }
    }
    
    private void MapRelacionamento(){
        Relacionamento r=null;
        Tabela t=null;
        Tabela tr=null;
        Object[] a=null;
        Object[] v=null;
        Object[] arestas=null;
        int i;
        int j;
        System.out.println("Relacionamentos: "+Integer.toString(Relacionamentos.size()));
        while(Relacionamentos.size() >0){
            r=(Relacionamento)Relacionamentos.poll();
            if(r.isTotal())
                continue;
            v=graph.getAdjacentes(r,Aresta.SOURCE);
            arestas=graph.getArestas(r,Aresta.SOURCE);
            if(v.length<=1)
                continue;
            else if(v.length==2 && !r.isAssociativa() && !(((Aresta)arestas[0]).getMax()>1 && ((Aresta)arestas[1]).getMax()>1)){
                if(((Aresta)arestas[0]).getMax()==1 && ((Aresta)arestas[1]).getMax()==1){
                    if(((Aresta)arestas[0]).getMin()==0){
                        tr=Tabelas.get((Entidade)v[1]);
                        t=Tabelas.get((Entidade)v[0]);
                    }else{
                        tr=Tabelas.get((Entidade)v[0]);
                        t=Tabelas.get((Entidade)v[1]);
                    }
                }else{
                    if(((Aresta)arestas[0]).getMax()>1){
                        t=Tabelas.get((Entidade)v[0]);
                        tr=Tabelas.get((Entidade)v[1]);
                    }else{
                        t=Tabelas.get((Entidade)v[1]);
                        tr=Tabelas.get((Entidade)v[0]);
                    }
                }
                
                key2fk(tr,t);

//                a=tr.getPrimo();
//                // adiciona atributos primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addFK(tr,(AtributoSerial)a[i]);
//                }
//
//                a=tr.getFKPrimo();
//                // adiciona atributos primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addFK((FK)a[i]);
//                }                
                
                
            }else{
                //Verifica se ja tem todos dados
                i=0;
                while(i<v.length && Tabelas.containsKey(v[i])){
                    i++;
                }
                if(i!=v.length){//Volta para Fila se falta alguma coisa
                    Relacionamentos.offer(r);
                    continue;
                }
                
                t=new Tabela(graph.convertValueToString(r));
                
                atr2table(r,t);
//                // pega todos os atributos nao primos
//                a = r.valuesArrayAtributos();
//
//                // adiciona atributos nao primos a relacao
//                for (i = 0; i < a.length; i++){
//                    t.addAtributo((Atributo)a[i]);
//                }
                
                if(r.isAssociativa()){
                    
                    key2table(r,t);
//                    // pega todos os atributos nao primos
//                    a = r.valuesArrayAtributosPrimos();
//
//                    // adiciona atributos nao primos a relacao
//                    for (i = 0; i < a.length; i++){
//                        t.addPrimo((Atributo)a[i]);
//                    }
                    
                    for (j = 0; j < v.length; j++){
                        tr=Tabelas.get(v[j]);
                        
                        key2fk(tr,t);

//                        a=tr.getPrimo();
//                        // adiciona atributos primos a relacao
//                        for (i = 0; i < a.length; i++){
//                            t.addFK(tr,(AtributoSerial)a[i]);
//                        }
//
//                        a=tr.getFKPrimo();
//                        // adiciona atributos primos a relacao
//                        for (i = 0; i < a.length; i++){
//                            t.addFK((FK)a[i]);
//                        }
                    }
                }else{
                    for (j = 0; j < v.length; j++){
                        tr=Tabelas.get(v[j]);
                        
                        key2fkk(tr,t);
                        
//                        a=tr.getPrimo();
//                        // adiciona atributos primos a relacao
//                        for (i = 0; i < a.length; i++){
//                            t.addFKPrimo(tr,(AtributoSerial)a[i]);
//                        }
//
//                        a=tr.getFKPrimo();
//                        // adiciona atributos primos a relacao
//                        for (i = 0; i < a.length; i++){
//                            t.addFKPrimo((FK)a[i]);
//                        }
                        
                    }
                }
                Tabelas.put(r,t);
            }
        }
    }
    
    private void key2fkk(Tabela source,Tabela target){
        Object[] a=source.getPrimo();
        int i;
        // adiciona atributos primos a relacao
        for (i = 0; i < a.length; i++){
            target.addFKPrimo(source,(AtributoSerial)a[i]);
        }

        a=source.getFKPrimo();
        // adiciona atributos primos a relacao
        for (i = 0; i < a.length; i++){
            target.addFKPrimo((FK)a[i]);
        }
    }
    
    private void key2fk(Tabela source,Tabela target){
        Object[] a=source.getPrimo();
        int i;
        // adiciona atributos primos a relacao
        for (i = 0; i < a.length; i++){
            target.addFK(source,(AtributoSerial)a[i]);
        }

        a=source.getFKPrimo();
        // adiciona atributos primos a relacao
        for (i = 0; i < a.length; i++){
            target.addFK((FK)a[i]);
        }
        
    }
    
    private void key2table(BlocoAtributosGraphCell e,Tabela t){
        // pega todos os atributos primos
        Object[] a = e.valuesArrayAtributosPrimos();
        int i;
        // adiciona atributos primos a relacao
        for (i = 0; i < a.length; i++){
            t.addPrimo((Atributo)a[i]);
        }
    }
    
    private void atr2table(BlocoAtributosGraphCell e,Tabela t){
        // pega todos os atributos primos
        Object[] a = e.valuesArrayAtributos();
        int i;
        // adiciona atributos primos a relacao
        for (i = 0; i < a.length; i++){
            if(((Atributo)a[i]).MultiValorado){
                System.out.println("Multi Valorado naum tratado");
            }else
                t.addAtributo((Atributo)a[i]);
        }
    }
    
    public String getSQL(){
        return getSQL("SQL92");
    }
    
    public String getSQL(String SGBD){
        Object[] t=Tabelas.values().toArray();
        String r="";
        int i=0;
        while(i<t.length){
            try {
                r+=((Tabela)t[i]).getSQL(SGBD)+"\n\n";
            } catch (Exception e) {
                r+="--ERROR in TABLE "+((Tabela)t[i]).getNome()+" ->"+e.getMessage()+"\n\n";
            }
            i++;
        }
        return r;
    }
    
    public String getMER(){
        Object[] t=Tabelas.values().toArray();
        String r="";
        int i=0;
        while(i<t.length){
            try {
                r+=((Tabela)t[i]).getMER()+"\n";
            } catch (Exception e) {
                r+="###ERROR in TABLE "+((Tabela)t[i]).getNome()+" ->"+e.getMessage()+"\n";
            }
            i++;
        }
        return r;
    }
    
}
